﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;

namespace ICodeShare.UI.Controls.Assists
{
    /// <summary>
    /// 可输入控件附加属性
    /// </summary>
    public static class InputAssist
    {

        #region SelectAllOnFocus 获取焦点后选中全部文本

        public static void SetSelectAllOnFocus(DependencyObject obj, bool value)
        {
            obj.SetValue(SelectAllOnFocusProperty, value);
        }

        [AttachedPropertyBrowsableForType(typeof(TextBoxBase))]
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        [AttachedPropertyBrowsableForType(typeof(ComboBox))]
        public static bool GetSelectAllOnFocus(DependencyObject obj)
        {
            return (bool)obj.GetValue(SelectAllOnFocusProperty);
        }

        public static readonly DependencyProperty SelectAllOnFocusProperty = DependencyProperty.RegisterAttached(
            "SelectAllOnFocus",
            typeof(bool),
            typeof(InputAssist),
            new FrameworkPropertyMetadata(false, OnSelectAllOnFocusChanged));

        static void OnSelectAllOnFocusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is TextBox)
            {
                var txtBox = d as TextBox;

                if ((bool)e.NewValue)
                {
                    txtBox.GotFocus += TextBoxGotFocus;

                }
                else
                {
                    txtBox.GotFocus -= TextBoxGotFocus;
                }
            }
            else if (d is PasswordBox)
            {
                var passBox = d as PasswordBox;

                if ((bool)e.NewValue)
                {
                    passBox.GotFocus += PasswordGotFocus;
                }
                else
                {
                    passBox.GotFocus -= PasswordGotFocus;
                }
            }
        }

        static void TextBoxGotFocus(object sender, RoutedEventArgs e)
        {
            var txtBox = sender as TextBox;
            if (txtBox == null)
                return;
            if (GetSelectAllOnFocus(txtBox))
            {
                txtBox.Dispatcher.BeginInvoke((Action)(txtBox.SelectAll));
            }
        }

        static void PasswordGotFocus(object sender, RoutedEventArgs e)
        {
            var passBox = sender as PasswordBox;
            if (passBox == null)
                return;
            if (GetSelectAllOnFocus(passBox))
            {
                passBox.Dispatcher.BeginInvoke((Action)(passBox.SelectAll));
            }
        }
        #endregion

        #region 清空按钮

        #region CanClearText 是否可清空

        /// <summary>
        /// Get where show the shadow for waiting data
        /// </summary>
        [AttachedPropertyBrowsableForType(typeof(TextBoxBase))]
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        [AttachedPropertyBrowsableForType(typeof(ComboBox))]
        [AttachedPropertyBrowsableForType(typeof(DatePicker))]
        public static bool GetCanClearText(DependencyObject element)
        {
            return (bool)element.GetValue(CanClearTextProperty);
        }

        /// <summary>
        /// Set where show the shadow for waiting data
        /// </summary>
        public static void SetCanClearText(DependencyObject element, bool value)
        {
            element.SetValue(CanClearTextProperty, value);
        }

        /// <summary>
        /// DependencyProperty for <see cref="CanClearText" /> property.
        /// </summary>
        public static readonly DependencyProperty CanClearTextProperty =DependencyProperty.RegisterAttached(
            "CanClearText", 
            typeof(bool), 
            typeof(InputAssist),
            new FrameworkPropertyMetadata(false,FrameworkPropertyMetadataOptions.Inherits));

        #endregion CanClearText 是否可清空

        #region IsClearTextButtonBehaviorEnabled 清空按钮的命令是否可用

        /// <summary>
        /// Gets the clear text button behavior.
        /// </summary>
        [AttachedPropertyBrowsableForType(typeof(Button))]
        public static bool GetIsClearTextButtonBehaviorEnabled(Button d)
        {
            return (bool)d.GetValue(IsClearTextButtonBehaviorEnabledProperty);
        }

        /// <summary>
        /// Sets the clear text button behavior.
        /// </summary>
        [AttachedPropertyBrowsableForType(typeof(Button))]
        public static void SetIsClearTextButtonBehaviorEnabled(Button obj, bool value)
        {
            obj.SetValue(IsClearTextButtonBehaviorEnabledProperty, value);
        }

        /// <summary>
        /// The clear text button behavior property. It sets a click event to the button if the value is true.
        /// </summary>
        public static readonly DependencyProperty IsClearTextButtonBehaviorEnabledProperty = DependencyProperty.RegisterAttached(
            "IsClearTextButtonBehaviorEnabled",
            typeof(bool), 
            typeof(InputAssist),
            new FrameworkPropertyMetadata(false, IsClearTextButtonBehaviorEnabledChanged));


        private static void IsClearTextButtonBehaviorEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var clearButton = d as Button;
            if (e.OldValue != e.NewValue && clearButton != null)
            {
                clearButton.Click -= ClearButtonClicked;
                if ((bool)e.NewValue)
                {
                    clearButton.Click += ClearButtonClicked;
                }
            }
        }

        public static void ClearButtonClicked(object sender, RoutedEventArgs e)
        {
            var button = ((Button)sender);
            var parent = VisualTreeHelper.GetParent(button);
            while (!(parent is TextBox || parent is PasswordBox || parent is ComboBox || parent is DatePicker))
            {
                parent = VisualTreeHelper.GetParent(parent);
            }

            if (GetCanClearText(parent))
            {
                if (parent is TextBox)
                {
                    ((TextBox)parent).Clear();
                }
                else if (parent is PasswordBox)
                {
                    ((PasswordBox)parent).Clear();
                }
                else if (parent is ComboBox)
                {
                    if (((ComboBox)parent).IsEditable)
                    {
                        ((ComboBox)parent).Text = string.Empty;
                    }
                    ((ComboBox)parent).SelectedItem = null;
                }
                else if (parent is DatePicker)
                {
                    ((DatePicker)parent).SelectedDate = null;
                    ((DatePicker)parent).Text = string.Empty;
                }
            }
        }
        #endregion

        #region ClearButtonContent 附加按钮内容

        /// <summary>
        /// Allows on (IsChecked) content to be provided on supporting <see cref="ToggleButton"/> styles.
        /// </summary>
        /// <param name="element"></param>
        /// <param name="value"></param>
        public static void SetClearButtonContent(DependencyObject element, object value)
        {
            element.SetValue(ClearButtonContentProperty, value);
        }

        /// <summary>
        /// Allows on (IsChecked) content to be provided on supporting <see cref="ToggleButton"/> styles.
        /// </summary>
        public static object GetClearButtonContent(DependencyObject element)
        {
            return (object)element.GetValue(ClearButtonContentProperty);
        }

        /// <summary>
        /// Allows on (IsChecked) content to be provided on supporting <see cref="ToggleButton"/> styles.
        /// </summary>
        public static readonly DependencyProperty ClearButtonContentProperty = DependencyProperty.RegisterAttached(
            "ClearButtonContent", typeof(object), typeof(InputAssist), new PropertyMetadata(default(object)));

        #endregion

        #endregion

        #region 附加按钮

        #region AttachButtonEnable 附加按钮是否可用

        /// <summary>
        /// Get where show the shadow for waiting data
        /// </summary>
        [AttachedPropertyBrowsableForType(typeof(TextBoxBase))]
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        public static bool GetAttachButtonEnable(DependencyObject element)
        {
            return (bool)element.GetValue(AttachButtonEnableProperty);
        }

        /// <summary>
        /// Set where show the shadow for waiting data
        /// </summary>
        public static void SetAttachButtonEnable(DependencyObject element, bool value)
        {
            element.SetValue(AttachButtonEnableProperty, value);
        }

        /// <summary>
        /// DependencyProperty for <see cref="AttachButtonEnable" /> property.
        /// </summary>
        public static readonly DependencyProperty AttachButtonEnableProperty =
            DependencyProperty.RegisterAttached("AttachButtonEnable", typeof(bool), typeof(InputAssist), new UIPropertyMetadata(false));

        #endregion AttachButtonEnable 是否可清空

        #region IsAttachButtonBehaviorEnabled 附加按钮的命令是否可用

        /// <summary>
        /// Gets the clear text button behavior.
        /// </summary>
        [AttachedPropertyBrowsableForType(typeof(Button))]
        public static bool GetIsAttachButtonBehaviorEnabled(Button d)
        {
            return (bool)d.GetValue(IsAttachButtonBehaviorEnabledProperty);
        }

        /// <summary>
        /// Sets the clear text button behavior.
        /// </summary>
        public static void SetIsAttachButtonBehaviorEnabled(Button obj, bool value)
        {
            obj.SetValue(IsAttachButtonBehaviorEnabledProperty, value);
        }

        /// <summary>
        /// The clear text button behavior property. It sets a click event to the button if the value is true.
        /// </summary>
        public static readonly DependencyProperty IsAttachButtonBehaviorEnabledProperty = DependencyProperty.RegisterAttached(
            "IsAttachButtonBehaviorEnabled",
            typeof(bool), typeof(InputAssist),
            new FrameworkPropertyMetadata(false, IsAttachButtonBehaviorEnabledChanged));


        private static void IsAttachButtonBehaviorEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var attachButton = d as Button;
            if (e.OldValue != e.NewValue && attachButton != null)
            {
                attachButton.Click -= AttachButtonClicked;
                if ((bool)e.NewValue)
                {
                    attachButton.Click += AttachButtonClicked;
                }
            }
        }

        public static void AttachButtonClicked(object sender, RoutedEventArgs e)
        {
            var button = ((Button)sender);
            var parent = VisualTreeHelper.GetParent(button);
            while (!(parent is TextBox || parent is PasswordBox || parent is ComboBox))
            {
                parent = VisualTreeHelper.GetParent(parent);
            }

            var command = GetAttachCommand(parent);
            if (command != null && command.CanExecute(parent))
            {
                var commandParameter = GetAttachCommandParameter(parent);

                command.Execute(commandParameter ?? parent);
            }

            UIElement parentUIElement = parent as UIElement;
            parentUIElement.RaiseEvent(new RoutedEventArgs(AttachClickEvent, null));
        }
        #endregion

        #region AttachContent 附加按钮内容

        /// <summary>
        /// Allows on (IsChecked) content to be provided on supporting <see cref="ToggleButton"/> styles.
        /// </summary>
        /// <param name="element"></param>
        /// <param name="value"></param>
        public static void SetAttachContent(DependencyObject element, object value)
        {
            element.SetValue(AttachContentProperty, value);
        }

        /// <summary>
        /// Allows on (IsChecked) content to be provided on supporting <see cref="ToggleButton"/> styles.
        /// </summary>
        public static object GetAttachContent(DependencyObject element)
        {
            return (object)element.GetValue(AttachContentProperty);
        }

        /// <summary>
        /// Allows on (IsChecked) content to be provided on supporting <see cref="ToggleButton"/> styles.
        /// </summary>
        public static readonly DependencyProperty AttachContentProperty = DependencyProperty.RegisterAttached(
            "AttachContent", typeof(object), typeof(InputAssist), new PropertyMetadata(default(object)));

        #endregion

        #region AttachTemplate 附加按钮样式

        /// <summary>
        /// Allows an on (IsChecked) template to be provided on supporting <see cref="ToggleButton"/> styles.
        /// </summary>
        public static void SetAttachTemplate(DependencyObject element, ControlTemplate value)
        {
            element.SetValue(AttachTemplateProperty, value);
        }

        /// <summary>
        /// Allows an on (IsChecked) template to be provided on supporting <see cref="ToggleButton"/> styles.
        /// </summary>
        public static ControlTemplate GetAttachTemplate(DependencyObject element)
        {
            return (ControlTemplate)element.GetValue(AttachTemplateProperty);
        }

        /// <summary>
        /// Allows an on (IsChecked) template to be provided on supporting <see cref="ToggleButton"/> styles.
        /// </summary>
        public static readonly DependencyProperty AttachTemplateProperty = DependencyProperty.RegisterAttached(
            "AttachTemplate", typeof(ControlTemplate), typeof(InputAssist), new PropertyMetadata(null));

        #endregion

        #region AttachCommand 附加按钮命令

        public static ICommand GetAttachCommand(DependencyObject d)
        {
            return (ICommand)d.GetValue(AttachCommandProperty);
        }

        public static void SetAttachCommand(DependencyObject obj, ICommand value)
        {
            obj.SetValue(AttachCommandProperty, value);
        }

        public static readonly DependencyProperty AttachCommandProperty = DependencyProperty.RegisterAttached(
            "AttachCommand",
            typeof(ICommand),
            typeof(InputAssist),
            new FrameworkPropertyMetadata(null));
        #endregion

        #region AttachCommandParameter 附加按钮命令参数

        public static object GetAttachCommandParameter(DependencyObject d)
        {
            return (object)d.GetValue(AttachCommandParameterProperty);
        }

        public static void SetAttachCommandParameter(DependencyObject obj, object value)
        {
            obj.SetValue(AttachCommandParameterProperty, value);
        }

        public static readonly DependencyProperty AttachCommandParameterProperty = DependencyProperty.RegisterAttached(
            "AttachCommandParameter",
            typeof(object),
            typeof(InputAssist),
            new FrameworkPropertyMetadata(null));


        #endregion

        #region AttachClickEvent 附加按钮单击事件
        [AttachedPropertyBrowsableForType(typeof(TextBox))]
        public static void AddAttachClickHandler(DependencyObject d, RoutedEventHandler handler)
        {
            UIElement e = d as UIElement;
            if (e != null)
            {
                e.AddHandler(InputAssist.AttachClickEvent, handler);
            }
        }

        public static void RemoveAttachClickHandler(DependencyObject d, RoutedEventHandler handler)
        {
            UIElement e = d as UIElement;
            if (e != null)
            {
                e.RemoveHandler(InputAssist.AttachClickEvent, handler);
            }
        }

        public static readonly RoutedEvent AttachClickEvent = EventManager.RegisterRoutedEvent(
            "AttachClick",
            RoutingStrategy.Bubble,
            typeof(RoutedEventHandler),
            typeof(InputAssist));
        #endregion

        #endregion

        #region IsReadOnly=true 输入控件只读

        #region ReadOnlyBackground 输入控件只读只读时，背景颜色

        /// <summary>
        /// Gets the brush used to draw the mouse pressed background.
        /// </summary>
        [AttachedPropertyBrowsableForType(typeof(TextBoxBase))]
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        [AttachedPropertyBrowsableForType(typeof(ComboBox))]
        public static Brush GetReadOnlyBackground(DependencyObject element)
        {
            return (Brush)element.GetValue(ReadOnlyBackgroundProperty);
        }

        /// <summary>
        /// Sets the brush used to draw the mouse pressed background.
        /// </summary>
        public static void SetReadOnlyBackground(DependencyObject element, Brush value)
        {
            element.SetValue(ReadOnlyBackgroundProperty, value);
        }

        /// <summary>
        /// DependencyProperty for <see cref="ReadOnlyBackground" /> property.
        /// </summary>
        public static readonly DependencyProperty ReadOnlyBackgroundProperty = DependencyProperty.RegisterAttached(
            "ReadOnlyBackground",
            typeof(Brush),
            typeof(InputAssist),
            new FrameworkPropertyMetadata(Brushes.Transparent,
                FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits));

        #endregion ReadOnlyBackground 鼠标按下时背景颜色

        #region ReadOnlyBorderBrush 输入控件只读只读时，边框颜色

        /// <summary>
        /// Gets the brush used to draw the focus border.
        /// </summary>
        [AttachedPropertyBrowsableForType(typeof(TextBoxBase))]
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        [AttachedPropertyBrowsableForType(typeof(ComboBox))]
        public static Brush GetReadOnlyBorderBrush(DependencyObject element)
        {
            return (Brush)element.GetValue(ReadOnlyBorderBrushProperty);
        }

        /// <summary>
        /// Sets the brush used to draw the focus border.
        /// </summary>
        public static void SetReadOnlyBorderBrush(DependencyObject element, Brush value)
        {
            element.SetValue(ReadOnlyBorderBrushProperty, value);
        }

        /// <summary>
        /// DependencyProperty for <see cref="ReadOnlyBorderBrush" /> property.
        /// </summary>
        public static readonly DependencyProperty ReadOnlyBorderBrushProperty = DependencyProperty.RegisterAttached(
            "ReadOnlyBorderBrush",
            typeof(Brush),
            typeof(InputAssist),
            new FrameworkPropertyMetadata(Brushes.Transparent,
                FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits));

        #endregion ReadOnlyBorderBrush 获取焦点后边框颜色

        #region ReadOnlyForeground 输入控件只读只读时，字体颜色

        /// <summary>
        /// Gets the brush used to draw the mouse pressed font color.
        /// </summary>
        [AttachedPropertyBrowsableForType(typeof(TextBoxBase))]
        [AttachedPropertyBrowsableForType(typeof(PasswordBox))]
        [AttachedPropertyBrowsableForType(typeof(ComboBox))]
        public static Brush GetReadOnlyForeground(DependencyObject element)
        {
            return (Brush)element.GetValue(ReadOnlyForegroundProperty);
        }

        /// <summary>
        /// Sets the brush used to draw the mouse pressed font color.
        /// </summary>
        public static void SetReadOnlyForeground(DependencyObject element, Brush value)
        {
            element.SetValue(ReadOnlyForegroundProperty, value);
        }

        /// <summary>
        /// DependencyProperty for <see cref="ReadOnlyForeground" /> property.
        /// </summary>
        public static readonly DependencyProperty ReadOnlyForegroundProperty = DependencyProperty.RegisterAttached(
            "ReadOnlyForeground",
            typeof(Brush),
            typeof(InputAssist),
            new FrameworkPropertyMetadata(Brushes.Transparent,
                FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits));

        #endregion ReadOnlyForeground 选中时字体颜色

        #endregion IsReadOnly 获取焦点时
    }
}
